/*
servidor-archivos-concurrente
    Copyright (C) 2012 Darío López Padial 
    @bukosabino

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#include "xdr.h"
#include <stdio.h>
#include <stdlib.h>
#include <rpc/pmap_clnt.h>
#include <string.h>
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>

#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif

static void
servidorarchivos_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
	union {
		char *crear_1_arg;
		dobleString escribir_1_arg;
		char *leer_1_arg;
		dobleString renombrar_1_arg;
		char *creardir_1_arg;
		char *borrardir_1_arg;
	} argument;
	char *result;
	xdrproc_t _xdr_argument, _xdr_result;
	char *(*local)(char *, struct svc_req *);

	if (fork () == 0) {
		switch (rqstp->rq_proc) {
		case NULLPROC:
			(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
			exit(1);

		case CREAR:
			_xdr_argument = (xdrproc_t) xdr_wrapstring;
			_xdr_result = (xdrproc_t) xdr_int;
			local = (char *(*)(char *, struct svc_req *)) crear_1_svc;
			break;

		case ESCRIBIR:
			_xdr_argument = (xdrproc_t) xdr_dobleString;
			_xdr_result = (xdrproc_t) xdr_wrapstring;
			local = (char *(*)(char *, struct svc_req *)) escribir_1_svc;
			break;

		case LEER:
			_xdr_argument = (xdrproc_t) xdr_wrapstring;
			_xdr_result = (xdrproc_t) xdr_wrapstring;
			local = (char *(*)(char *, struct svc_req *)) leer_1_svc;
			break;

		case RENOMBRAR:
			_xdr_argument = (xdrproc_t) xdr_dobleString;
			_xdr_result = (xdrproc_t) xdr_int;
			local = (char *(*)(char *, struct svc_req *)) renombrar_1_svc;
			break;

		case CREARDIR:
			_xdr_argument = (xdrproc_t) xdr_wrapstring;
			_xdr_result = (xdrproc_t) xdr_int;
			local = (char *(*)(char *, struct svc_req *)) creardir_1_svc;
			break;

		case BORRARDIR:
			_xdr_argument = (xdrproc_t) xdr_wrapstring;
			_xdr_result = (xdrproc_t) xdr_int;
			local = (char *(*)(char *, struct svc_req *)) borrardir_1_svc;
			break;

		default:
			svcerr_noproc (transp);
			exit(1);
		}
		memset ((char *)&argument, 0, sizeof (argument));
		if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
			svcerr_decode (transp);
			exit(1);
		}
		result = (*local)((char *)&argument, rqstp);
		if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
			svcerr_systemerr (transp);
		}
		if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
			fprintf (stderr, "%s", "unable to free arguments");
			exit (1);
		}
		exit(0);
	} else {
		return svc_run ();
	}
}

int
main (int argc, char **argv)
{
	register SVCXPRT *transp;

	pmap_unset (SERVIDORARCHIVOS, SERVIDORARCHIVOSVERS);

	transp = svcudp_create(RPC_ANYSOCK);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create udp service.");
		exit(1);
	}
	if (!svc_register(transp, SERVIDORARCHIVOS, SERVIDORARCHIVOSVERS, servidorarchivos_1, IPPROTO_UDP)) {
		fprintf (stderr, "%s", "unable to register (SERVIDORARCHIVOS, SERVIDORARCHIVOSVERS, udp).");
		exit(1);
	}

	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create tcp service.");
		exit(1);
	}
	if (!svc_register(transp, SERVIDORARCHIVOS, SERVIDORARCHIVOSVERS, servidorarchivos_1, IPPROTO_TCP)) {
		fprintf (stderr, "%s", "unable to register (SERVIDORARCHIVOS, SERVIDORARCHIVOSVERS, tcp).");
		exit(1);
	}

	svc_run ();
	fprintf (stderr, "%s", "svc_run returned");
	exit (1);
	/* NOTREACHED */
}
